/* $Id: channel.h jjs $ */
/*
   Copyright (C) 2007 by Jurjen Stellingwerff <jurjen@stwerff.xs4all.nl>
   Part of the Moros Project http://moros.sourceforge.net/

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/
#ifndef __CHANNEL_H
#define __CHANNEL_H

#include "buffer.h"
#include <list>
#include <vector>
#include <sigc++/signal.h>

typedef long size;


using namespace std;

/// Functions on a specific type of connection

class connection {
public:
	/// Function to read data, return -1 on error or bytes
	virtual int read(char *buffer, size length)=0;

	/// Function to write data, return -1 on error or bytes
	virtual int write(const char *buffer, size length)=0;

	/// Function to close the current socket/file
	virtual void close()=0;

	/// Length of the file, allways -1 on sockets
	virtual size length()=0;
	virtual ~connection() {}
};

#define TYPE_SOCKET 1
#define TYPE_FILE 2
#define TYPE_SERVER 3
#define TYPE_IMPORT 4

/// Data of and operations on an open connection

class channel {
  private:
	/// Input buffer
	buffer *input_;
	/// Amount still to read before the current batch is complete
	size to_input_;
	/// Output buffer
	buffer *output_;
	/// Remember when the last data was succesfully writen or read for timeout calculation
	long last_;
	/// States of a connection
	///
	/// STATE_CLOSED		: 0 There is no socket to read or no file to read/write
	/// STATE_WAITING	: 1 Try to read the 8 bytes header with the amount to data to expect
	/// STATE_READING	: 2 Try to read the data block
	/// STATE_WRITING	: 3 Try to send the resulting data, return to waiting after that
	enum READY_STATE { STATE_CLOSED, STATE_WAITING, STATE_READING, STATE_WRITING};
	/// Current state of the connection
	int state;
	/// Check if this session is a correct one
	bool check_session();
	/// List of files to leave data in
	list<std::string> write_files;
	/// File to read from
	int readf;
	/// File to write to
	int writef;
	/// Poll routines for file transfer
	void file_poll(long time);
	/// Number of errors on this channel
	int errors;


  public:
	/// initiate a new channel, 1=socket based, 2=file based (also give file size), 3=server_socker, 4=import based
	channel(int channeltype, long time);

	/// payload of this channel
	void *payload;

	/// Free the buffers of this channel
	void close(void);
	/// Pointer to the current key
	std::string key;
	/// Pointer to the current value
	std::string value;
	/// Ip address of the connected client or the hostname of the server
	std::string ip;
	/// Port number on the server
	int port;
	/// Unique id for the channel
	unsigned int id;

	/// Scan for the next key in the input
	bool next();
	/// Check if the next key in the input is the given key
	bool peek(string key);
	/// Write this key to the other side of the connection or the file
	void write(const std::string key, const std::string value);
	/// Write this numeric key to the other side of the connection or the file
	void write(const std::string key, const long value);
	/// Send the finished data to the other side
	void send();
	/// Read data from this file
	void fread(const std::string file);
	/// Write the next data to this file
	void fwrite(const std::string file);
	/// Finish writing to the file or close the socket
	void finish();

	/// Poll for new data, with the current time
	void poll(long time);
	/// Connection class with read/write/close functions
	/// Dont change connection type on a running channel
	connection *stream;
	/// Indication that the channel is finished, only needed for communicate class
	/// Use finish() to indicate it is finished
	bool finished;
	/// Function to call when new data is ready to read
	sigc::signal<void, channel*> handler;

	/// type of the connection (1=client_socket, 2=file, 3=server_socket, 4=import)
	int type;

	/// Send session data to the other party
	void send_session(long time);
	/// related communication record
	class communicate *comm;
	/// lock till correct credentials are found
	bool lock;

};

#endif // __CHANNEL_H
